package com.issac.springbootredis.distributed_lock;

/*
*   引入lua脚本解决分布式锁超时问题：
*       假设某个场景:
*           如果业务操作时间比较耗时，容易导致业务未完成但锁已经超时释放，
*           进入的第二个线程的锁会被前一个线程的del()方法释放，导致第三个线程进来，
*           以此类推 循环无尽会造成混乱
*       解决思路：
*           1.避免执行耗时操作
*           2.对value进行校验，在每个线程执行的时候，设定一个随机的value,
*           在del()前校验value值，不一致则跳过，一致则释放
*
            //分布式锁方法2：在redis2.8中，新增了setnx可以增加过期时间，让方法原子操作

*       对于第二个解决方案：
*           由于在校验value时，需要get值、equals值、释放锁，三个不具备原子性的操作，会有挂了的风险
*           所以，我们可以在redis中引入lua脚本
*
*       lua脚本的优点：
*           1.redis官方内置了lua脚本环境
*           2.lua脚本可以在redis客户端原子的一次执行多个命令
*           3.网络问题会影响redis性能，使用lua脚本可以让多个命令一次执行，可以有效解决网络给redis带来的性能问题
*
*       在redis中如何使用lua脚本:
*           1.提前在redis服务端中写好lua脚本，通过script load 获取lua脚本SHA1值，在redis客户端中调用(推荐)
*           2.在客户端中通过资源文件/字符串拼接等方法向redis服务端发送lua脚本
*
*       lua脚本的编写：
*
*       执行思路:
*           1.redis服务端创建lua脚本
*           [root@localhost ~]# mkdir luaTest
            [root@localhost ~]# cd luaTest
            [root@localhost luaTest]# vi releaseValueEqual.luaTest
            脚本内容：
                if redis.call("get",KEYS[1]) == ARGV[1] then
                return redis.call("del",KEY[1])
                else
                return 0
                end
*
*           2.script load 一个 SHA1 值  :（我本机的"b8059ba43af6ffe8bed3db65bac35d452f8115d8"
*             管道 cat luaTest/releaseValueEqual.luaTest | redis-cli -a issac script load --pipe

*
*
*
* */

import com.issac.springbootredis.jedispool.Redis;
import redis.clients.jedis.params.SetParams;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.UUID;

public class luaTest {
    public static void main(String[] args) {
        Redis redis = new Redis();
        for (int i = 0; i < 2; i++) {//6. 同时执行两次实验效果
            redis.exectue(jedis -> {
                //1. 先获取一个随机字符串
                String value = UUID.randomUUID().toString();
                //2. 获取一个锁
                String set = jedis.set("k1", value, new SetParams().nx().ex(5));
                //3. 判断是否成功拿到锁
                if (set!=null && set.equals("OK")){
                    //4. 执行业务代码
                    jedis.set("qq","1151546");
                    System.out.println(jedis.get("qq"));
                    //5. 释放资源 放lua脚本sha1
                    jedis.evalsha("b8059ba43af6ffe8bed3db65bac35d452f8115d8", Arrays.asList("k1"),Arrays.asList(value));
                    // 5.1 在客户端发送lua脚本
                    //5.1.1 jedis.eval()拼接;
                    //5.1.2 IO流读取resources
                }else {
                    System.out.println("没拿到锁");
                }
            });
        }

    }

}
